<#include "/templates/taglibs.ftl" />
<#include "/templates/function.ftl" />
<!DOCTYPE html>
<html lang="zh-cn">
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" href="${contextPath}/assets/plugins/layui/css/layui.css" media="all" />
        <style>
            p {
                margin-bottom: 10px;
                font-size: 15px;
                color: #393D49;
                font-weight: 400;
                line-height: 1.8;
            }
            .site-content {
                background-color: #fff;
                padding: 20px 0 10px 20px;
            }
            .site-h1 {
                margin-bottom: 20px;
                line-height: 60px;
                padding-bottom: 10px;
                color: #393D49;
                border-bottom: 1px solid #eee;
                font-size: 28px;
                font-weight: 400;
            }
        </style>
    </head>
    <body>
        <div class="layui-fluid layui-container">
            <div class="layui-row site-content">
                <div class="layui-col-md12">
                    <h1 class="site-h1">jdbcTemplate配置多个数据源</h1>
                    <p>实际运用中，很多时候会遇到一些慢查询，如果用查询主库，会导致锁表等，导致用户端使用时很卡。</p>
                    <p>为了解决此类问题，配置多个数据源，去主库做增加、修改操作，去从库查询数据。</p>
                    <fieldset class="layui-elem-field layui-field-title site-title">
                        <legend><a name="get">连接池介绍</a></legend> 
                    </fieldset>
                    <p>首先说下连接池:</p>
                    <p>数据源即DataSource, 在java中有很多对DataSource的实现， 如C3P0, Druid. 从连接池中获取某个数据库的连接， 减少创建和关闭连接带来的性能消耗。 同时基本上所有的连接池实现都有对于连接池的一些配置如 用户名密码，url, maxWait,maxActive 等等</p>
                    <p>一个数据源管理一组相同属性的数据库的连接</p>
                    <fieldset class="layui-elem-field layui-field-title site-title">
                        <legend><a name="get">多数据源的应用场景</a></legend> 
                    </fieldset>
                    <p>到目前为止， 遇到过下面几种多数据源的应用场景:</p>
                    <p>1、分库分表</p>
                    <p>当业务变得越来越复杂， 数据变得越来月庞大， 即使简单的sql查询性能也不见有多好， 这时候我们可以采用分库分表的方式。 当然切分的方式有很多，比如按照业务垂直切分， 在这里不做讨论。</p>
                    <p>2、读写分离</p>
                    <p>对数据库的更新以及删除等操作和查询操作是在不同数据库进行的。</p>
                    <br/>
                    <p>在一个数据库进行操作， 对于开发是最理想的， 拆分数据库在一定程度会增大模块的复杂性，根据自己的需求， 恰当使用多数据源。</p>
                    <fieldset class="layui-elem-field layui-field-title site-title">
                        <legend><a name="get">多数据源的使用</a></legend> 
                    </fieldset>
                    <p>多数据源即在一个应用中配置多个不同的连接池,对于数据源的使用是相对容易的。</p>
                    <p>多数据的实现方式也有不同的方式方法，此处介绍使用<b>jdbcTemplate</b>方式实现多数据源配置</p>
                    <br/>
                    <p>实现步骤：</p>
                    <p>1、配置文件中(db.properties)配置两个数据库的连接信息</p>
                    <pre class="layui-code" lay-skin="notepad" lay-title="db.properties">
#============================#
#===== Database sttings =====#
#============================#
jdbc.name = SystemDatasource
jdbc.driver=com.mysql.jdbc.Driver
#\u6570\u636e\u5e93\u5730\u5740
jdbc.url=jdbc:mysql://127.0.0.1:3306/opendao_master_db?useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;zeroDateTimeBehavior=convertToNull
#\u7528\u6237\u540d
jdbc.username=root
#\u5bc6\u7801
jdbc.password=root
#\u521d\u59cb\u5316\u65f6\uff0c\u6570\u636e\u5e93\u8fde\u63a5\u6c60\u4e2d\u7684\u8fde\u63a5\u6570\u91cf
jdbc.pool.initialSize=1
#\u6570\u636e\u5e93\u4fdd\u6301\u7684\u6700\u5c0f\u8fde\u63a5\u6570
jdbc.pool.minIdle=1
#\u6700\u5927\u6d3b\u8dc3\u8fde\u63a5\u6570
jdbc.pool.maxActive=500
#\u6570\u636e\u5e93\u83b7\u53d6\u8fde\u63a5\u7684\u8d85\u65f6\u503c
jdbc.pool.maxWait=60000
jdbc.pool.timeBetweenEvictionRunsMillis=60000
# \u914d\u7f6e\u4e00\u4e2a\u8fde\u63a5\u5728\u6c60\u4e2d\u6700\u5c0f\u751f\u5b58\u7684\u65f6\u95f4\uff0c\u5355\u4f4d\u662f\u6beb\u79d2
jdbc.pool.minEvictableIdleTimeMillis = 300000
# \u6570\u636e\u5e93\u6d4b\u8bd5
jdbc.test.validationQuery=SELECT 'x' 
jdbc.test.testWhileIdle=true
jdbc.test.testOnBorrow=false
jdbc.test.testOnReturn=false
jdbc.pscache.poolPreparedStatements=true
jdbc.pscache.maxPoolPreparedStatementPerConnectionSize=100

jdbc.filters=stat,config

#============================#
#===== slave sttings =====#
#============================#
slave.jdbc.name =QrtzDatasource
#slave.jdbc.driver = oracle.jdbc.driver.OracleDriver
slave.jdbc.driver=com.mysql.jdbc.Driver
#\u6570\u636e\u5e93\u5730\u5740
slave.jdbc.url=jdbc:mysql://127.0.0.1:3306/opendao_salve_db?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;zeroDateTimeBehavior=convertToNull
#\u7528\u6237\u540d
#slave.jdbc.username=UUMS
slave.jdbc.username=root
#\u5bc6\u7801
#slave.jdbc.password=COMBOBOX
slave.jdbc.password=root
#\u521d\u59cb\u5316\u65f6\uff0c\u6570\u636e\u5e93\u8fde\u63a5\u6c60\u4e2d\u7684\u8fde\u63a5\u6570\u91cf
slave.jdbc.pool.initialSize=1
#\u6570\u636e\u5e93\u4fdd\u6301\u7684\u6700\u5c0f\u8fde\u63a5\u6570
slave.jdbc.pool.minIdle=1
#\u6700\u5927\u6d3b\u8dc3\u8fde\u63a5\u6570
slave.jdbc.pool.maxActive=500
#\u6570\u636e\u5e93\u83b7\u53d6\u8fde\u63a5\u7684\u8d85\u65f6\u503c
slave.jdbc.pool.maxWait=60000
slave.jdbc.pool.timeBetweenEvictionRunsMillis=60000
# \u914d\u7f6e\u4e00\u4e2a\u8fde\u63a5\u5728\u6c60\u4e2d\u6700\u5c0f\u751f\u5b58\u7684\u65f6\u95f4\uff0c\u5355\u4f4d\u662f\u6beb\u79d2
slave.jdbc.pool.minEvictableIdleTimeMillis = 300000
# \u6570\u636e\u5e93\u6d4b\u8bd5
#slave.jdbc.test.validationQuery=SELECT 'x' FROM DUAL
slave.jdbc.test.validationQuery=SELECT 'x'
slave.jdbc.test.testWhileIdle=true
slave.jdbc.test.testOnBorrow=false
slave.jdbc.test.testOnReturn=false
slave.jdbc.pscache.poolPreparedStatements=true
slave.jdbc.pscache.maxPoolPreparedStatementPerConnectionSize=100
slave.jdbc.filters=stat,config
                    </pre>
                    <p>2、SpringMVC主配置文件中配置双数据源信息：</p>
                    <p>（一）首先配置加载库连接信息:</p>
                    <pre class="layui-code" lay-skin="notepad" lay-title="02-data-access-config.xml">
<context:property-placeholder ignore-unresolvable="true" location="classpath:dbsetting.properties"/>
                    </pre>
                    <br/>
                    <p>（二）再配置双数据源：</p>
                    <pre class="layui-code" lay-skin="notepad" lay-title="02-data-access-config.xml">
<!-- 配置dataSource数据源 -->
<bean id="masterDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <property name="name" value="${jdbc.name}" />
    <!-- 数据源驱动类可不写，Druid默认会自动根据URL识别DriverClass -->
    <property name="driverClassName" value="${jdbc.driver}" />
    
    <!-- 基本属性 url、user、password -->
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    
    <!-- 配置初始化大小、最小、最大 -->
    <property name="initialSize" value="${jdbc.pool.initialSize}" />
    <property name="minIdle" value="${jdbc.pool.minIdle}" /> 
    <property name="maxActive" value="${jdbc.pool.maxActive}" />
    
    <!-- 配置获取连接等待超时的时间 -->
    <property name="maxWait" value="${jdbc.pool.maxWait}" />
    
    <!-- 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒 -->
    <property name="timeBetweenEvictionRunsMillis" value="${jdbc.pool.timeBetweenEvictionRunsMillis}" />
    
    <!-- 配置一个连接在池中最小生存的时间，单位是毫秒 -->
    <property name="minEvictableIdleTimeMillis" value="${jdbc.pool.minEvictableIdleTimeMillis}" />
    
    <property name="validationQuery" value="${jdbc.test.validationQuery}" />
    <property name="testWhileIdle" value="${jdbc.test.testWhileIdle}" />
    <property name="testOnBorrow" value="${jdbc.test.testOnBorrow}" />
    <property name="testOnReturn" value="${jdbc.test.testOnReturn}" />
    
    <!-- 打开PSCache，并且指定每个连接上PSCache的大小（Oracle使用）-->
    <property name="poolPreparedStatements" value="${jdbc.pscache.poolPreparedStatements}" />
    <property name="maxPoolPreparedStatementPerConnectionSize" value="${jdbc.pscache.maxPoolPreparedStatementPerConnectionSize}" /> 
    
    <!-- 配置监控统计拦截的filters -->
    <property name="filters" value="${jdbc.filters},wall" /> 
    
    <property name="proxyFilters">
      <list>
          <ref bean="wall-filter"/>
      </list>
    </property>
</bean>

<!-- 配置slaveSource数据源 -->
<bean id="slaveDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <property name="name" value="slaveDataSource" />
    <!-- 数据源驱动类可不写，Druid默认会自动根据URL识别DriverClass -->
    <property name="driverClassName" value="${slave.jdbc.driver}" />
    
    <!-- 基本属性 url、user、password -->
    <property name="url" value="${slave.jdbc.url}" />
    <property name="username" value="${slave.jdbc.username}" />
    <property name="password" value="${slave.jdbc.password}" />
    
    <!-- 配置初始化大小、最小、最大 -->
    <property name="initialSize" value="${slave.jdbc.pool.initialSize}" />
    <property name="minIdle" value="${slave.jdbc.pool.minIdle}" /> 
    <property name="maxActive" value="${slave.jdbc.pool.maxActive}" />
    
    <!-- 配置获取连接等待超时的时间 -->
    <property name="maxWait" value="${slave.jdbc.pool.maxWait}" />
    
    <!-- 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒 -->
    <property name="timeBetweenEvictionRunsMillis" value="${slave.jdbc.pool.timeBetweenEvictionRunsMillis}" />
    
    <!-- 配置一个连接在池中最小生存的时间，单位是毫秒 -->
    <property name="minEvictableIdleTimeMillis" value="${slave.jdbc.pool.minEvictableIdleTimeMillis}" />
    
    <property name="validationQuery" value="${slave.jdbc.test.validationQuery}" />
    <property name="testWhileIdle" value="${slave.jdbc.test.testWhileIdle}" />
    <property name="testOnBorrow" value="${slave.jdbc.test.testOnBorrow}" />
    <property name="testOnReturn" value="${slave.jdbc.test.testOnReturn}" />
    
    <!-- 打开PSCache，并且指定每个连接上PSCache的大小（Oracle使用）-->
    <property name="poolPreparedStatements" value="${slave.jdbc.pscache.poolPreparedStatements}" />
    <property name="maxPoolPreparedStatementPerConnectionSize" value="${slave.jdbc.pscache.maxPoolPreparedStatementPerConnectionSize}" /> 
    
    <!-- 配置监控统计拦截的filters -->
    <property name="filters" value="${slave.jdbc.filters}" /> 
</bean>
                    </pre>
                    <br/>
                    <p>两个数据源都采用阿里巴巴的Druid数据库连接池，连接池配置请参考druid官网，案例使用druid的推荐配置</p>
                    <p>（三）配置JdbcTemplate模板</p>
                    <pre class="layui-code" lay-skin="notepad" lay-title="02-data-access-config.xml">
<!-- JdbcTemplate -->
<bean id="masterJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="masterDataSource"></property>
</bean>

<!-- JdbcTemplate -->
<bean id="salveDdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="salveDataSource"></property>
</bean>

                    </pre>
                    <br/>
                    <p>3、使用数据源</p>
                    <p>在需要使用数据源的DAO类中，注入要使用的数据源即可</p>
                    <pre class="layui-code" lay-skin="notepad">
    @Autowired
    @Qualifier("masterJdbcTemplate")
    private JdbcTemplate masterJdbcTemplate;

    @Autowired
    @Qualifier("slaveJdbcTemplate")
    private JdbcTemplate salveJdbcTemplate;
                    </pre>
                </div>
            </div>
        </div>
    </body>
    <script type="text/javascript" src="${contextPath}/assets/plugins/layui/layui.js"></script>
    <script>
        layui.use('code', function(){ 
            layui.code({
                encode: true
            }); 
          });
    </script>
</html>